package cagt.tools.probability;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import cagt.tools.Card;

/**
 * Probability toolkit is a collection of tools used to count the probability of
 * occurence of cards and their sequences.
 * 
 * @author Konrad Sza�kowski
 * 
 */
public abstract class ProbabilityToolkit {
	private ProbabilityToolkit() {
	}

	/**
	 * Probability of drawing card from some collection.
	 * 
	 * @param card
	 *            Card.
	 * @param collection
	 *            Collection.
	 * @return Probability of drawing a card from collection.
	 */
	public static <T extends Card> double probability(T card,
			Collection<T> collection) {
		int occurences = 0;
		for (Card c : collection) {
			if (c.equals(card)) {
				occurences++;
			}
		}
		return ((double) occurences) / ((double) collection.size());
	}

	/**
	 * Probability of drawing any of the cards from the collection.
	 * 
	 * @param cards
	 *            Cards.
	 * @param collection
	 *            Collection.
	 * @return Probability of drawing any of the cards from the collection.
	 */
	public static <T extends Card> double probability(Collection<T> cards,
			Collection<T> collection) {
		int occurences = 0;
		for (Card c : collection) {
			for (Card card : cards) {
				if (c.equals(card)) {
					occurences++;
				}
			}
		}
		return occurences < collection.size() ? ((double) occurences)
				/ ((double) collection.size()) : 1.0;
	}

	/**
	 * Probability of drawing card sequence.
	 * 
	 * @param cards
	 *            Card sequence.
	 * @param collection
	 *            Collection of cards.
	 * @return Probability of drawing a sequence from the collection.
	 */
	public static <T extends Card> double sequence(List<T> cards,
			Collection<T> collection) {
		return sequenceR(new ArrayList<Card>(cards), new ArrayList<Card>(
				collection));
	}

	private static <T extends Card> double sequenceR(List<T> cards,
			Collection<T> collection) {
		// Stop term
		if (cards.size() > collection.size() || cards.isEmpty()) {
			return 0.0;
		}
		// Take the first card
		Iterator<T> iterator = cards.iterator();
		T card = iterator.next();
		// Remove it
		iterator.remove();
		// Count probability
		double prob = probability(card, collection);
		// Remove from collection the card
		collection.remove(card);
		// Optimization
		if (prob <= 0.0) {
			return prob;
		}
		// Run recursively
		return prob * sequence(cards, collection);
	}
}
